package com.manong.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.manong.config.security.Utils;
import com.manong.dao.DepartmentMapper;
import com.manong.dao.SysSalaryMapper;
import com.manong.dao.UserMapper;
import com.manong.entity.Department;
import com.manong.entity.SysSalary;
import com.manong.entity.User;
import com.manong.service.SysSalaryService;
import com.manong.vo.CommonReqVo;
import com.manong.vo.SysSalaryVo;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 薪资(SysSalary)表服务实现类
 *
 */
@Service("sysSalaryService")
public class SysSalaryServiceImpl extends ServiceImpl<SysSalaryMapper, SysSalary> implements SysSalaryService {

    @Resource
    private DepartmentMapper departmentMapper;

    @Resource
    private UserMapper userMapper;


    @Override
    public IPage listAll(CommonReqVo commonReqVo) {
        User user = Utils.getUser();
        Integer isAdmin = user.getIsAdmin();
        val userId1 = user.getId();
        //分页查询必备，填充分页参数
        IPage<SysSalary> page = new Page<SysSalary>(commonReqVo.getPageNo(),
                commonReqVo.getPageSize());
        //条件构造器，便于 为查询添加查询条件的
        LambdaQueryWrapper<SysSalary> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //如果 commonReqVo.getUserIds() 集合为空，就不添加 根据用户id 的查询条件，否则 就会 添加查询条件（更加用户id）  ，
        //会添加  user_id in ( 1,3,6)
        lambdaQueryWrapper.in(Objects.equals(1, isAdmin)&&!CollectionUtils.isEmpty(commonReqVo.getUserIds()), SysSalary::getUserId, commonReqVo.getUserIds());
        // 如果 commonReqVo.getTime() 不为空， 就添加 查询条件  salary_time = ‘2023--12-13 00:00:00’
        lambdaQueryWrapper.eq(commonReqVo.getTime()!=null,SysSalary::getSalaryTime,commonReqVo.getTime());
        // 如果不是超级管理员 只能查看自己的信息
        lambdaQueryWrapper.eq(!Objects.equals(1, isAdmin), SysSalary::getUserId,userId1);

        //分页查询
        final IPage<SysSalary> page1 = this.page(page, lambdaQueryWrapper);
        // 这是查询所有部门数据，因为 SysFinancialExpenses 中不存储 部门名称， 是根据部门id 进行外键关联的，
        // 所以返回给前端的时候需要把部门名称也返回给前端
        final List<Department> departments = departmentMapper.selectList(null);
        // 这是查询所有用户数据，因为 SysSalary 中不存储 用户名， 是根据用户id 进行外键关联的，所以返回给前端的时候需要把用户名称也返回给前端
        final List<User> users = userMapper.selectList(new QueryWrapper<>());
        // 拿到 分页查询结果中的数据集合
        final List<SysSalary> records = page1.getRecords();
        System.out.println(page1.getTotal());
        IPage<SysSalaryVo> sysSalaryVoIPage = new Page<>();
        // 这是 拷贝属性，因为 IPage<SysSalary> 中 只有部门id字段，没有部门名称字段，
        // 而返回给前端的时候需要部门名称，所以新创建一个对象，包含部门名称
        //也没有用户名称字段， 也需要返回用户名称字段给前端
        BeanUtils.copyProperties(page1, sysSalaryVoIPage);
        List<SysSalaryVo> sysSalaryVos = new ArrayList<>();
        //这里是 for循环每个分页结果中的数据对象，填充 部门名称字段
        for (SysSalary record : records) {
            final Long deptId = record.getDeptId();
            //stream 是jdk8自带的方便操作集合的流，eg，对list元素进行分组，聚合，求最大值，最小值，等等，
            // 几行代码就可以完成通过for循环传统操作几十行代码完成的功能
            //匹配部门
            final Optional<Department> first = departments.stream()
                    .filter(d -> Objects.equals(deptId, d.getId()))
                    .findFirst();
            SysSalaryVo one = new SysSalaryVo();
            BeanUtils.copyProperties(record, one);
            //如果 系统中不存在指定部门id的数据，就不填充部门名称，否则就填充（正常情况下会有的）
            if (first.isPresent()) {
                final String departmentName = first.get().getDepartmentName();
                one.setDeptName(departmentName);
            }
            final Long userId = record.getUserId();
            //stream 是jdk8自带的方便操作集合的流，eg，对list元素进行分组，聚合，求最大值，最小值，等等，几行代码就可以完成通过for循环传统操作几十行代码完成的功能
            // 匹配用户
            final Optional<User> first1 = users.stream()
                    .filter(u -> Objects.equals(u.getId(), userId))
                    .findFirst();
            //如果 系统中不存在指定用户id的数据，就不填充用户名称，否则就填充（正常情况下会有的）
            if (first1.isPresent()) {
                final String username = first1.get().getUsername();
                one.setUserName(username);
            }

            sysSalaryVos.add(one);
        }
        //把填充好部门名称的数据塞到返回体里面，然后返回给前端
        sysSalaryVoIPage.setRecords(sysSalaryVos);
        return sysSalaryVoIPage;
    }

    @Override
    public Boolean delete1(CommonReqVo commonReqVo) {
        //        直接调用mybatis 的批量删除方法，删除数据
        return this.removeBatchByIds(commonReqVo.getMainIds());
    }

    @Override
    public Boolean save1(SysSalary sysSalary) {

        //        之间调用 mybatis的 更新或者保存方法，进行更新或者保存
//        注意，根据主键id是否存在，以及主键id是否在数据库中存在来判断更新或者插入，
        return this.saveOrUpdate(sysSalary);
    }

    @Override
    public List<SysSalaryVo> chart(CommonReqVo commonReqVo) {
        List<SysSalaryVo> charts = new ArrayList<>();
        // 查询薪水信息，查询全部
        final List<SysSalary> list = this.list();
        // 如果没有查询到数据，则直接返回 ，不需要继续下面 数据转换为响应的数据结构 的逻辑处理
        if (CollectionUtils.isEmpty(list)) {
            return charts;
        }
        //数据库查询操作，将结果赋值给变量
        // 薪水表中只有部门id并没有部门名称，界面上显示的是部门名称，所以需要先查询出部门信息数据，在根据部门id转换成部门名称
        final List<Department> departments = departmentMapper.selectList(null);
        // 将薪水信息结果集合数据根据部门id分组，聚合每个部门内的薪水的数据
        for (Map.Entry<Long, List<SysSalary>> longListEntry : list.stream()
                .collect(Collectors.groupingBy(SysSalary::getDeptId))
                .entrySet()) {
            // 部门id
            final Long deptId = longListEntry.getKey();
            // longListEntry.getValue() 根据部门id分组后的薪水数据，可能有多个，然后映射出薪水信息中的  salary字段，再求和
            final double sum = longListEntry.getValue()
                    .stream().mapToDouble(SysSalary::getSalary)
                    .sum();
            // 根本部门id 筛选出部门信息数据
            final Department department = departments.stream()
                    .filter(d -> Objects.equals(deptId, d.getId()))
                    .findFirst().get();
            // 部门名称
            final String departmentName = department.getDepartmentName();
            // 返回给前端的响应内容
            SysSalaryVo one = new SysSalaryVo();
            one.setDeptId(deptId);
            one.setDeptName(departmentName);
            one.setSalary(sum);
            charts.add(one);
        }

        return charts;
    }
}
